package org.cmisarium.xcmis.fsprovider;

import org.xcmis.spi.CmisConstants;
import org.xcmis.spi.ConstraintException;
import org.xcmis.spi.ContentStream;
import org.xcmis.spi.FolderData;
import org.xcmis.spi.StorageException;
import org.xcmis.spi.TypeManager;
import org.xcmis.spi.TypeNotFoundException;
import org.xcmis.spi.basic.BasicObjectData;
import org.xcmis.spi.model.AccessControlEntry;
import org.xcmis.spi.model.BaseType;
import org.xcmis.spi.model.Property;
import org.xcmis.spi.model.TypeDefinition;
import org.xcmis.spi.model.impl.DateTimeProperty;
import org.xcmis.spi.model.impl.StringProperty;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class ObjectDataImpl extends BasicObjectData
{

   protected final String rootPath;

   protected File file;

   protected TypeManager typeManager;

   public ObjectDataImpl(File file, String rootPath, TypeManager typeManager)
   {
      this.file = file;
      this.rootPath = rootPath;
      this.typeManager = typeManager;

   }

   /**
    * {@inheritDoc}
    */
   public List<AccessControlEntry> getACL(boolean onlyBasicPermissions)
   {
      return new ArrayList<AccessControlEntry>();
   }

   /**
    * {@inheritDoc}
    */
   public String getTypeId()
   {
      return this.getTypeDefinition().getId();
   }

   /**
    * {@inheritDoc}
    */
   public BaseType getBaseType()
   {
      return getTypeDefinition().getBaseId();
   }

   public ContentStream getContentStream(String streamId)
   {

      if (file.isDirectory())
         return null;
      else
         return ((DocumentDataImpl)this).getContentStream();

   }

   public String getCreatedBy()
   {

      return "n/a";
   }

   public Calendar getCreationDate()
   {
      Calendar cal = Calendar.getInstance();
      cal.setTimeInMillis(file.lastModified());
      return cal;
   }

   public Calendar getLastModificationDate()
   {

      Calendar cal = Calendar.getInstance();
      cal.setTimeInMillis(file.lastModified());
      return cal;
   }

   public String getLastModifiedBy()
   {

      return "n/a";
   }

   public String getName()
   {
      return file.getName();
   }

   public String getObjectId()
   {

      return PathCoder.pathToId(path(file.getAbsolutePath(), rootPath));
   }

   public FolderData getParent() throws ConstraintException
   {

      if (file.getAbsolutePath().equals(this.rootPath))
         throw new ConstraintException("Root folder");

      return new FolderDataImpl(file.getParentFile(), rootPath, typeManager);
   }

   public Map<String, Property<?>> getProperties()
   {

      Map<String, Property<?>> props = new HashMap<String, Property<?>>();

      props.put(CmisConstants.OBJECT_ID, new StringProperty(CmisConstants.OBJECT_ID, CmisConstants.OBJECT_ID,
         CmisConstants.OBJECT_ID, CmisConstants.OBJECT_ID, getObjectId()));
      props.put(CmisConstants.OBJECT_TYPE_ID, new StringProperty(CmisConstants.OBJECT_TYPE_ID,
         CmisConstants.OBJECT_TYPE_ID, CmisConstants.OBJECT_TYPE_ID, CmisConstants.OBJECT_TYPE_ID, getTypeId()));
      props.put(CmisConstants.BASE_TYPE_ID, new StringProperty(CmisConstants.BASE_TYPE_ID, CmisConstants.BASE_TYPE_ID,
         CmisConstants.BASE_TYPE_ID, CmisConstants.BASE_TYPE_ID, getBaseType().value()));

      props.put(CmisConstants.NAME, new StringProperty(CmisConstants.NAME, CmisConstants.NAME, CmisConstants.NAME,
         CmisConstants.NAME, getName()));
      props.put(CmisConstants.CREATED_BY, new StringProperty(CmisConstants.CREATED_BY, CmisConstants.CREATED_BY,
         CmisConstants.CREATED_BY, CmisConstants.CREATED_BY, getCreatedBy()));
      props.put(CmisConstants.LAST_MODIFIED_BY, new StringProperty(CmisConstants.LAST_MODIFIED_BY,
         CmisConstants.LAST_MODIFIED_BY, CmisConstants.LAST_MODIFIED_BY, CmisConstants.LAST_MODIFIED_BY,
         getLastModifiedBy()));

      props.put(CmisConstants.CREATION_DATE, new DateTimeProperty(CmisConstants.CREATION_DATE,
         CmisConstants.CREATION_DATE, CmisConstants.CREATION_DATE, CmisConstants.CREATION_DATE, getCreationDate()));
      props.put(CmisConstants.LAST_MODIFICATION_DATE, new DateTimeProperty(CmisConstants.LAST_MODIFICATION_DATE,
         CmisConstants.LAST_MODIFICATION_DATE, CmisConstants.LAST_MODIFICATION_DATE,
         CmisConstants.LAST_MODIFICATION_DATE, getLastModificationDate()));

      if (getBaseType() == BaseType.FOLDER)
      {
         props.put(CmisConstants.PATH, new StringProperty(CmisConstants.PATH, CmisConstants.PATH, CmisConstants.PATH,
            CmisConstants.PATH, ((FolderData)this).getPath()));
      }

      return props;
   }

   public TypeDefinition getTypeDefinition()
   {
      try
      {
         if (file.isDirectory())
            return typeManager.getTypeDefinition(CmisConstants.FOLDER, true);
         else
            return typeManager.getTypeDefinition(CmisConstants.DOCUMENT, true);
      }
      catch (TypeNotFoundException e)
      {
         // IT IS IMPOSSIBLE
         throw new NullPointerException(e.getMessage());
      }
   }

   public void setName(String name)
   {

      File newFile = new File(this.file.getParent(), name);
      file.renameTo(newFile);
      file = newFile;

   }

   public void setProperties(Map<String, Property<?>> properties)
   {

      for (Property<?> prop : properties.values())
      {
         setProperty(prop);
      }

   }

   public void setProperty(Property<?> property)
   {

      if (property.getId().equals(CmisConstants.NAME))
         setName((String)property.getValues().get(0));

   }

   public void delete() throws StorageException
   {
      if (!file.delete())
      {
         throw new StorageException("Can not delete object " + file.getName());
      }
   }

   protected static String path(String theFilePath, String theRootPath)
   {
      if (theFilePath.equals(theRootPath))
      {
         return "";
      }
      return theFilePath.substring(theRootPath.length() + 1, theFilePath.length());

   }

}
